package com.magi.builder;

import com.magi.core.AppUtils;
import com.magi.core.TableMetaData;

public class DynamicMysqlBuilder implements IDynamicSQLBuilder {

    private final DynamicXmlSQLBuilder xmlSQLBuilder = new DynamicXmlSQLBuilder();


    private String getDefaultWhereBody(TableMetaData.Column[] columns) {
        StringBuilder whereBody = new StringBuilder(Identifiers.CRLF);
        boolean hasPKFlag = false;
        for (TableMetaData.Column column : columns) {
            if (column.isPrimaryKey()) {
                whereBody.append(Identifiers.TAB)
                        .append(getDefaultIf(column))
                        .append(Identifiers.CRLF);
                hasPKFlag = true;
            }
        }
        if (!hasPKFlag) {
            whereBody.append(Identifiers.TAB)
                    .append(this.getDefaultIf(columns[0])).append(Identifiers.CRLF);
        }
        return whereBody.toString();
    }

    private String getDefaultIf(TableMetaData.Column column) {
        return xmlSQLBuilder.getIf(
                column.getName() + " != null",
                "AND " + column.getName() + " == #{" + AppUtils.columnName2fieldName(column.getName()) + "}");
    }

    @Override
    public String insert(String tableName, TableMetaData.Column[] columns) {
        StringBuilder sqlBuilder = new StringBuilder("INSERT INTO ").append(Identifiers.CRLF)
                .append(Identifiers.TAB)
                .append(tableName)
                .append(Identifiers.SPACE)
                .append(Identifiers.PARENTHESIS_L);
        StringBuilder values = new StringBuilder("VALUES")
                .append(Identifiers.SPACE)
                .append(Identifiers.PARENTHESIS_L);
        for (TableMetaData.Column column : columns) {
            sqlBuilder.append(column.getName())
                    .append(Identifiers.COMMA)
                    .append(Identifiers.SPACE);
            values.append("#{")
                    .append(AppUtils.columnName2fieldName(column.getName()))
                    .append("}")
                    .append(Identifiers.COMMA)
                    .append(Identifiers.SPACE);
        }
        // get rid of last comma
        sqlBuilder.replace(sqlBuilder.length() - 2, sqlBuilder.length(), "");
        values.replace(values.length() - 2, values.length(), "");


        sqlBuilder.append(Identifiers.PARENTHESIS_R);
        values.append(Identifiers.PARENTHESIS_R);
        sqlBuilder.append(Identifiers.CRLF).append(values);
        return sqlBuilder.toString();
    }

    @Override
    public String select(String tableName, TableMetaData.Column[] columns) {
        StringBuilder sqlBuilder = new StringBuilder("SELECT");
        sqlBuilder.append(Identifiers.SPACE);
        for (TableMetaData.Column column : columns) {
            if (columns.length > 2) {
                sqlBuilder.append(Identifiers.CRLF)
                        .append(Identifiers.TAB);
            }
            sqlBuilder.append(column.getName())
                    .append(Identifiers.SPACE)
                    .append("AS")
                    .append(Identifiers.SPACE)
                    .append(AppUtils.columnName2fieldName(column.getName()))
                    .append(Identifiers.COMMA)
                    .append(Identifiers.SPACE);
        }

        // get rid of last comma
        sqlBuilder.replace(sqlBuilder.length() - 2, sqlBuilder.length() - 1, "");
        if (columns.length > 2) { sqlBuilder.append(Identifiers.CRLF); }
        sqlBuilder.append("FROM ")
                .append(tableName)
                .append(Identifiers.SPACE);


        sqlBuilder.append(Identifiers.CRLF)
                .append(xmlSQLBuilder.getWhere(this.getDefaultWhereBody(columns)));
        return sqlBuilder.toString();
    }

    @Override
    public String update(String tableName, TableMetaData.Column[] columns) {
        StringBuilder sqlBuilder = new StringBuilder("UPDATE");
        sqlBuilder.append(Identifiers.SPACE)
                .append(tableName)
                .append(Identifiers.SPACE);

        StringBuilder setBody = new StringBuilder(Identifiers.CRLF);
        for (TableMetaData.Column column : columns) {
            String fieldName = AppUtils.columnName2fieldName(column.getName());
            setBody.append(Identifiers.TAB)
                    .append(xmlSQLBuilder.getIf(
                            fieldName + " != null",
                            column.getName() + " == #{" + fieldName + "}, "))
                    .append(Identifiers.CRLF);
        }
        sqlBuilder.append(Identifiers.CRLF)
                .append(xmlSQLBuilder.getSet(setBody.toString()))
                .append(Identifiers.CRLF)
                .append(xmlSQLBuilder.getWhere(this.getDefaultWhereBody(columns)));
        return sqlBuilder.toString();
    }

    @Override
    public String delete(String tableName, TableMetaData.Column[] columns) {
        StringBuilder sqlBuilder = new StringBuilder("DELETE FROM").append(Identifiers.SPACE)
                .append(tableName)
                .append(Identifiers.SPACE)
                .append(Identifiers.CRLF);
                sqlBuilder.append(xmlSQLBuilder.getWhere(this.getDefaultWhereBody(columns)));
        return sqlBuilder.toString();
    }

    public static void main(String[] args) {
        IDynamicSQLBuilder sqlBuilder = new DynamicMysqlBuilder();
        System.out.println(sqlBuilder.select("selectTable", new TableMetaData.Column[]{
                new TableMetaData.Column("VARCHAR", "test_col"),
                new TableMetaData.Column("VARCHAR", "test_col"),
                new TableMetaData.Column("VARCHAR", "test_col"),
        }));

        System.out.println(Identifiers.CRLF);

        System.out.println(sqlBuilder.update("updateTable", new TableMetaData.Column[]{
                new TableMetaData.Column("VARCHAR", "test_col"),
                new TableMetaData.Column("VARCHAR", "test_col"),
                new TableMetaData.Column("VARCHAR", "test_col"),
        }));

        System.out.println(Identifiers.CRLF);

        System.out.println(sqlBuilder.insert("insertTable", new TableMetaData.Column[]{
                new TableMetaData.Column("VARCHAR", "test_col"),
                new TableMetaData.Column("VARCHAR", "test_col"),
                new TableMetaData.Column("VARCHAR", "test_col"),
        }));

        System.out.println(Identifiers.CRLF);

        System.out.println(sqlBuilder.delete("deleteTable", new TableMetaData.Column[]{
                new TableMetaData.Column("VARCHAR", "test_col"),
                new TableMetaData.Column("VARCHAR", "test_col"),
                new TableMetaData.Column("VARCHAR", "test_col"),
        }));
    }
}
